// HTTPUpload provides a "nice" API to send a multipart HTTP(S) POST
// request using wininet.  It currently supports requests that contain
// a set of string parameters (key/value pairs), and a file to upload.

#ifndef COMMON_WINDOWS_HTTP_UPLOAD_H_
#define COMMON_WINDOWS_HTTP_UPLOAD_H_

#pragma warning(push)
// Disable exception handler warnings.
#pragma warning(disable: 4530)

#include <Windows.h>
#include <WinInet.h>

#include <map>
#include <string>
#include <vector>

namespace longkey_breakpad
{
	using std::string;
	using std::wstring;
	using std::map;
	using std::vector;

	class HTTPUpload
	{
	public:
		// Sends the given set of parameters, along with the contents of
		// upload_file, as a multipart POST request to the given URL.
		// file_part_name contains the name of the file part of the request
		// (i.e. it corresponds the name= attribute on an <input type="file">.
		// parameter names must contain only printable ASCII characters, 
		// and may not contain a quote (") character.
		// Only HTTP(S) URLs are currently supported. Returns true on success.
		// If the request is successful and response_body is non-NULL,
		// the response body will be returned in response_body.
		// If response_code is non-NULL, it will be set to the HTTP response code
		// received (or 0 if the request failed before getting an HTTP response).
		static bool SendRequest(const wstring &url, const map<wstring, wstring> &parameters,
			const wstring &upload_file, const wstring &file_part_name, int *timeout, 
			wstring *response_body, int *response_code);

	private:
		class AutoInternetHandle;

		// Retrieves the HTTP response. If NULL is passed in for response,
		// this merely checks (via the return value) that we were successfully
		// able to retrieve exactly as many bytes of content in the response as
		// were specified in the Content-Length header.
		static bool ReadResponse(HINTERNET request, wstring* response);

		// Generates a new multipart boundary for a POST request
		static wstring GenerateMultipartBoundary();

		// Generates a HTTP request header for a multipart form submit.
		static wstring GenerateRequestHeader(const wstring &boundary);

		// Given a set of parameters, an upload filename, and a file part name,
		// generates a multipart request body string with these parameters
		// and minidump contents. Returns true on success.
		static bool GenerateRequestBody(const map<wstring, wstring> &parameters,
			const wstring &upload_file, const wstring &file_part_name, const wstring &boundary, string *request_body);

		// Fills the supplied vector with the constents of filename.
		static bool GetFileContents(const wstring &filename, vector<char> *contents);

		// Converts a UTF8 string to UTF16.
		static wstring UTF8ToWide(const string &utf8);

		// Converts a UTF16 string to UTF8.
		static string WideToUTF8(const wstring &wide);

		// Checks that the given list of parameters has only printable
		// ASCII characters in the parameter name, and does not contain
		// any quote (") characters. Returns true if so.
		static bool CheckParameters(const map<wstring, wstring> &parameters);

		// No instances of this class should be created.
		// Disable all constructors, destructors, and opereator=.
		HTTPUpload();
		explicit HTTPUpload(HTTPUpload&);
		void operator=(const HTTPUpload&);
		~HTTPUpload();
	};
}

#pragma warning(pop)

#endif	// COMMON_WINDOWS_HTTP_UPLOAD_H_